package com.flying.acls.adapter.spring;

import com.flying.acls.domain.context.ExpressionContext;
import com.flying.acls.domain.context.UrlExprContextBuilder;
import com.flying.acls.domain.permission.ClassPermissionBuilder;
import com.flying.acls.domain.resource.NoOpUrlResourceBuilder;
import com.flying.acls.domain.service.AclService;
import com.flying.acls.domain.sid.PatternBasedSidBuilder;
import com.flying.acls.model.PermsExpr;
import com.flying.acls.model.PermsType;
import com.flying.acls.model.ResExpr;
import com.flying.acls.model.SidExpr;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;

import java.util.Collection;
import java.util.List;

public class UrlDecisionVoter implements AccessDecisionVoter<FilterInvocation> {
    @Autowired
    private UrlExprContextBuilder contextBuilder;
    @Autowired
    private NoOpUrlResourceBuilder resourceBuilder;
    @Autowired
    private PatternBasedSidBuilder sidBuilder;
    @Autowired
    private ClassPermissionBuilder permissionBuilder;
    @Autowired
    private AclService aclService;

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return attribute instanceof AclEntryConfigAttribute;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return clazz.isAssignableFrom(FilterInvocation.class);
    }

    @Override
    public int vote(Authentication authentication, FilterInvocation object, Collection<ConfigAttribute> attributes) {
        int result = ACCESS_ABSTAIN;
        ExpressionContext context = contextBuilder.build(AuthenticationExtractor.getPrincipal(authentication), object.getHttpRequest(), object.getRequest().getMethod());
        List<ResExpr> requiredResExprs = resourceBuilder.build(context, object);
        List<SidExpr> sidExprs = sidBuilder.build(context, AuthenticationExtractor.getPrincipalName(authentication), AuthenticationExtractor.getRoles(authentication));
        List<PermsExpr> requiredPermsExpr = permissionBuilder.build(PermsType.HTTP, object.getRequest().getMethod());
        if (aclService.isGranted(context, requiredResExprs, sidExprs, requiredPermsExpr)) {
            result = ACCESS_GRANTED;
        } else {
            result = ACCESS_DENIED;
        }
        return result;
    }
}





